using Core;
using Microsoft.Extensions.Options;
using SuperSocket;
using SuperSocket.Server;

namespace Server;

public sealed class PlayServer : SuperSocketService<BaseCommand>
{
    private readonly PacketDispatchOptions _dispatchOptions;
    private readonly IAsyncSessionContainer _sessionContainer;

    public PlayServer(
        IServiceProvider serviceProvider, 
        IOptions<ServerOptions> serverOptions,
        IOptions<PacketDispatchOptions> dispatchOptions)
        : base(serviceProvider, serverOptions)
    {
        _dispatchOptions = dispatchOptions.Value;
        _sessionContainer = this.GetAsyncSessionContainer();
    }

    internal ValueTask<BaseCommand> AddOrderAsync(CommandOrder order)
    {
        return SendAndReceivePacketAsync(order.TargetId, new BaseCommand
        {
            Order = order,
            Key = BaseCommand.Types.CommandType.AddOrder,
        });
    }

    internal async ValueTask<BaseCommand> SendAndReceivePacketAsync(
        ulong targetId,
        BaseCommand command)
    {
        var sessions = await _sessionContainer.GetSessionsAsync<PlaySession>(s => s.UserId == targetId);

        if (sessions == null)
            throw new OffLineException($"{targetId} 对方已离线");

        if (!sessions.Any())
            throw new OffLineException($"{targetId} 对方已离线");

        var session = sessions.First();

        using var source = new CancellationTokenSource(TimeSpan.FromSeconds(_dispatchOptions.Timeout));

        return await session.SendAndReceivePacketAsync(command, source.Token);
    }
}